/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @file  SpiSlave_Driver.h
 * @brief Semidrive. AUTOSAR 4.3.1 MCAL SpiSlave_Slave plugins.
 */

#ifndef SPI_SLV_DRIVER_H
#define SPI_SLV_DRIVER_H

#ifdef __cplusplus
extern "C" {
#endif
/*******************************************************************************
**                      Include Section                                       **
*******************************************************************************/
#if (SPI_SLV_DEV_ERROR_DETECT == STD_ON)
#include "Det.h"
#endif

/*******************************************************************************
**                      Version Information                                   **
*******************************************************************************/
/* AUTOSAR Release version information */
#define SPI_SLV_DRIVER_AR_RELEASE_MAJOR_VERSION SPI_SLV_AR_RELEASE_MAJOR_VERSION
#define SPI_SLV_DRIVER_AR_RELEASE_MINOR_VERSION SPI_SLV_AR_RELEASE_MINOR_VERSION
#define SPI_SLV_DRIVER_AR_RELEASE_REVISION_VERSION \
    SPI_SLV_AR_RELEASE_REVISION_VERSION

/* File version information */
#define SPI_SLV_DRIVER_SW_MAJOR_VERSION SPI_SLV_SW_MAJOR_VERSION
#define SPI_SLV_DRIVER_SW_MINOR_VERSION SPI_SLV_SW_MINOR_VERSION

/*******************************************************************************
**                      Global Symbols                                      **
*******************************************************************************/
/*******************************************************************************
**                      Global Data Types                                     **
*******************************************************************************/

/*******************************************************************************
**                      Function Prototypes                                   **
*******************************************************************************/
#define MUX_0 PIN_MUX_ALT0

typedef enum {
    SPI_SLV_SCPO0_SCPH0 = 0x0,
    SPI_SLV_SCPO0_SCPH1 = 0x1,
    SPI_SLV_SCPO1_SCPH0 = 0x2,
    SPI_SLV_SCPO1_SCPH1 = 0x3
} SpiSlave_clock_mode;

typedef struct SpiSlave_EBDataTypeTag {
    /*Buffer for data source */
    const SpiSlave_DataBufferType *SrcDataBufferPtr;
    /*Buffer for data destination */
    SpiSlave_DataBufferType *DesDataBufferPtr;
    /*Length of buffer */
    SpiSlave_NumberOfDataType Length;
} SpiSlave_EBDataType;

typedef enum SpiSlave_SeqQueueStatusTypeTag {
    SPI_SLV_SEQ_QUEUE_INIT = 0,
    SPI_SLV_SEQ_QUEUE_PENDING,
    SPI_SLV_SEQ_QUEUE_SCHEDULED,
    SPI_SLV_SEQ_QUEUE_IN_PROGRESS,
    SPI_SLV_SEQ_QUEUE_OK
} SpiSlave_SeqQueueStatusType;

#ifndef SPI_SLV_LEVEL_DELIVERED
#error "No define 'SPI_SLV_LEVEL_DELIVERED' "
#endif

#if ((SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_1) || (SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_2))

struct SpiSlave_list {
    struct SpiSlave_list *Next;
    struct SpiSlave_list *Prev;
};
/*PRQA S 0603  3*/
#ifndef _offsetof
#define _offsetof(type, member)  \
    ((uint32)(&((type *)0)->member))
#endif

#define SpiSlaveGetJobNode(ptr) \
    ((struct SpiSlave_JobNode *)(((uint32)(ptr)) - _offsetof(struct SpiSlave_JobNode, Node)))


#define SpiSlaveGetSeqNode(ptr) \
    ((struct SpiSlave_SeqNode *)(((uint32)(ptr)) - _offsetof(struct SpiSlave_SeqNode, Node)))

struct SpiSlave_JobNode {
    boolean IsActive;
    SpiSlave_JobType   JobId;
    SpiSlave_SequenceType   SeqId;
    struct SpiSlave_list Node;
};
enum {
    ASYNC_SLV_SCHE_UNINIT,
    ASYNC_SLV_SCHE_IDLE,
    ASYNC_SLV_SCHE_ACTIVE,
};
struct SpiSlave_SeqNode {
    /* seq id*/
    SpiSlave_SequenceType   SeqId;
    /* seq priorty*/
    uint8   Priorty;
    /* Can Interrupt ? */
    uint8   Interruptable;
    /* Job Queue list head */
    struct SpiSlave_list JobQueue;
    /* Cur Job index */
    struct SpiSlave_JobNode *CurJob;
    /* Seq Queue Node  */
    struct SpiSlave_list Node;
    /* seq in queue */
    uint8 SeqInQueue;
};
#endif


struct SpiSlave_Scheduler {
#if ((SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_1) || \
     (SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_2))
    uint8 State;
    /* scheduled Seq Count */
    uint8 ActiveJobCnt;
    /* need schedule Seq Count */
    uint8 PendingSeqCnt;
    /* Hardware status mask */
    uint32 HwStatusMask;
    /* Global variable for Async mode  */
    SpiSlave_AsyncModeType SchedulerMode;
    /* Seq Queue list head */
    struct SpiSlave_list  SeqQueue;
    /* Record the job currently being processed by each controller */
    struct SpiSlave_JobNode *JobCurr[SPI_SLV_TOTAL_HW_COUNT];
#else
#if  (SPI_SLV_SUPPORT_CONCURRENT_SYNC_TRANSMIT == STD_ON)
    /* Hardware status mask */
    uint32 HwStatusMask;
#endif
#endif

};

struct SpiSlaveBus {
    /* mld bus  */
    struct mld_spi_slv_module Bus;
    /* mld bus Priv parameter  */
    struct spi_slv_bus_priv   Bus_Priv;
};
struct SpiSlaveDevice {
    /* mld device */
    struct mld_spi_slv_device Device;
    /* mld device Priv parameter*/
    struct spi_slv_dev_priv   Device_Priv;
};
/* A variable which is going to access configptr for SpiSlave_ConfigType*/
struct SpiSlave_Driver_Handler {
    /* SpiSlave_Slave Controllers */
    struct SpiSlaveBus        SpiBus[SPI_SLV_TOTAL_HW_COUNT];
    /* SpiSlave_Slave Slave Device  */
    struct SpiSlaveDevice     SpiDevice[SPI_SLV_TOTAL_DEV_COUNT];
#if ((SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_1) || (SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_2))
    /* Job Note list item */
    struct SpiSlave_JobNode  JobNode[SPI_SLV_TOTAL_DEV_COUNT];
    /* Seq Note list item */
    struct SpiSlave_SeqNode  SeqNode[SPI_SLV_TOTAL_SEQ_COUNT];
#endif
    /* mld async vector item  */
    struct mld_spi_slv_async  SpiChannelCB[SPI_SLV_MAX_CHANNEL];
    /*BUFF data  valid state */
    SpiSlave_ChannelStateType  SpiSlave_SpiChannelState[SPI_SLV_MAX_CHANNEL];
    /* async state machine */
    SpiSlave_StatusType SpiSlave_HandlerAsyncStatus;
    /* sync state machine */
    SpiSlave_StatusType SpiSlave_HandlerStatus;
    /* store EB pointer */
    SpiSlave_EBDataType ExtBuff[SPI_SLV_TOTAL_CH_COUNT];
    /* Job result */
    SpiSlave_JobResultType JobResult[SPI_SLV_TOTAL_JOB_COUNT];
    /* Seq result */
    SpiSlave_SeqResultType SeqResult[SPI_SLV_TOTAL_SEQ_COUNT];
    /*Sync mode Seq Count */
    uint16  SpiSyncSeqActiveCnt;
    /* Async Seq Cancel status */
#if SPI_SLV_CANCEL_API == STD_ON
    uint8    SeqCancel[SPI_SLV_TOTAL_SEQ_COUNT];
#endif
#if ((SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_1) || \
     (SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_2 ) || \
     (SPI_SLV_SUPPORT_CONCURRENT_SYNC_TRANSMIT == STD_ON))
    /* async scheduler only useed in LEVELx  X > 0*/
    struct SpiSlave_Scheduler Scheduler;
#endif
    /* for rx ingnal dma mode*/
    uint32 dummyRxBuffer;
    /* for tx default mode */
    uint32 dummyTxBuffer;

};

extern struct SpiSlave_Driver_Handler *const SpiSlaveHandler[SPI_SLV_CFG_CORES];

/* To initialise basic Hardware Registers */
extern FUNC(Std_ReturnType, SPI_SLV_CODE) SpiSlave_HWInit(void);
/* To De-Initialise the Hardware unit */
extern FUNC(Std_ReturnType, SPI_SLV_CODE) SpiSlave_HWDeInit(void);
/* To perform basic DET checks related to channels */
extern FUNC(Std_ReturnType, SPI_SLV_CODE) SpiSlave_ChannelDetCheck(const SpiSlave_ChannelType Channel,
        const uint8 SId);
/* To perform basic Det Checks for sequence Transmission request */
extern FUNC(Std_ReturnType, SPI_SLV_CODE) SpiSlave_SeqIdDetCheck(const SpiSlave_SequenceType Sequence,
        const uint8 SId);
/* To transmits the sequence  */
extern FUNC(Std_ReturnType, SPI_SLV_CODE) SpiSlave_SeqSyncTransmit(SpiSlave_SequenceType SequenceId,
        const SpiSlave_SequenceCfgType *PtrSeqConfig);
/* This function reads the HW status from  DW_SSI_SR register */
extern  FUNC(SpiSlave_StatusType, SPI_SLV_CODE) SpiSlave_GetHWStatus(SpiSlave_HWUnitType HwUnit);
/* Initialise global  data.*/
extern FUNC(void, SPI_SLV_CODE) SpiSlave_InitData(void);
/* */
extern FUNC(void, SPI_SLV_CODE) SpiSlave_HwMainFunctionHandling(uint8 Hwidx);
/* */
extern Std_ReturnType SpiSlave_HwAsyncTransmit(SpiSlave_SequenceType Sequence);
/* */
extern void SpiSlave_AsyncModeSet(SpiSlave_AsyncModeType mode);

uint8 SpiSlave_GetCoreID(void);

#if (SPI_SLV_CANCEL_API == STD_ON)
void SpiSlave_SeqCancel(SpiSlave_SequenceType SeqId);
#endif

#if (SPI_SLV_DEV_ERROR_DETECT == STD_ON)
uint32 SpiSlave_GetChannelAssignCoreId(SpiSlave_ChannelType Channel);
uint32 SpiSlave_GetJobAssignCoreId(SpiSlave_JobType JobId);
uint32 SpiSlave_GetSequenceAssignCoreId(SpiSlave_SequenceType Sequence);
#endif

#if (SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_2)
void SpiSlave_TriggerOnceSchedule(void);
#endif

#ifdef __cplusplus
}
#endif

#endif /* SPI_SLV_DRIVER_H */

/*******************************************************************************
**                      End of File                                           **
*******************************************************************************/
